﻿using System;
using System.Collections;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityHFSM;
using moai_kun_v1;
[RequireComponent(typeof(MainPlayer))]
[RequireComponent(typeof(PlayerInput))]
public class FSMController : MonoBehaviour
{
    #region Unity 方法

    private void OnEnable()
    {
        InitPlayer();
        InitInput();
        
    }
    private void Start()
    {
        InitFSM();
    }

    public void Update()
    {
        UpdateFSM();
    }
    #endregion

    #region Input 输入
    private PlayerInput _playerInput;
    private Vector2 _moveInput;
    private bool _jumpInput;
    private bool _attackInput;
    private bool _reset;
    private void InitInput()
    {
        _playerInput = GetComponent<PlayerInput>();
    }
    public void MoveInput(InputAction.CallbackContext ctx)
    {

        _moveInput = ctx.ReadValue<Vector2>();
    }
    public void JumpInput(InputAction.CallbackContext ctx)
    {
        _jumpInput = ctx.ReadValueAsButton();
        if (ctx.phase == InputActionPhase.Performed)
        {
            DoJump();
        }
    }

    private void DoJump()
    {
        if (_player.CanJump())
        {
            _player.Jump();
        }

    }

    public void AttackInput(InputAction.CallbackContext ctx)
    {
        _attackInput = ctx.ReadValueAsButton();
    }
    public void ResetInput(InputAction.CallbackContext ctx)
    {
        _reset = ctx.ReadValueAsButton();
    }
    #endregion

    #region 控制
    private MainPlayer _player;
    private void InitPlayer()
    {
        _player = GetComponent<MainPlayer>();
    }
    #endregion

    #region FSM
    private StateMachine<PlayerStatus,PlayerEvent> _fsm;
    private StateMachine<PlayerStatus, OnGroundState,PlayerEvent> _onGroundFsm;
    private StateMachine<PlayerStatus, OnAirState, PlayerEvent> _onAirFsm;
    private void InitFSM()
    {
        _fsm = new StateMachine<PlayerStatus,  PlayerEvent>(this);
        _onGroundFsm = new StateMachine<PlayerStatus, OnGroundState, PlayerEvent>();
        _onAirFsm = new StateMachine<PlayerStatus, OnAirState, PlayerEvent>();

        _fsm.AddState(PlayerStatus.OnGround,_onGroundFsm);
        _fsm.AddState(PlayerStatus.OnAir,_onAirFsm);
        _fsm.AddState(PlayerStatus.Die,new PlayerDeathState(_player));
        _fsm.AddState(PlayerStatus.Attack,new PlayerAttackState(_player));

        _fsm.AddTransition(PlayerStatus.OnGround, PlayerStatus.OnAir,(state) =>!_player.OnGrounded);
        _fsm.AddTransition(PlayerStatus.OnAir,PlayerStatus.OnGround,(state)=>_player.OnGrounded);
        _fsm.AddTransitionFromAny(PlayerStatus.Die, (state) => _player.CanDie());
        _fsm.AddTransitionFromAny(PlayerStatus.Attack,(state)=>_player.CanAttack()&&_attackInput);
        _fsm.AddTransitionFromAny(PlayerStatus.Jump, (state) => _player.CanJump() && _jumpInput);

        _fsm.AddTransition(PlayerStatus.Attack, PlayerStatus.OnGround,(state) => _player.OnGrounded&&!_player.IsAttacking);
        _fsm.AddTransition(PlayerStatus.Attack, PlayerStatus.OnAir, (state) => !_player.OnGrounded && !_player.IsAttacking);

        _fsm.SetStartState(PlayerStatus.OnGround);

        _onGroundFsm.AddState(OnGroundState.Idle,new PlayerIdleState(_player));
        _onGroundFsm.AddState(OnGroundState.Move,new PlayerMoveState(_player));
        _onGroundFsm.AddState(OnGroundState.Pull,new PlayerPullStoneState(_player));
      
        _onGroundFsm.AddTransition(OnGroundState.Idle,OnGroundState.Move,(state)=>_moveInput.x!=0&&_player.CanMove());
        _onGroundFsm.AddTransition(OnGroundState.Move, OnGroundState.Idle, (state) => _moveInput.x == 0);
        _onGroundFsm.AddTransition(OnGroundState.Move,OnGroundState.Pull,(state)=>_player.CanPush());
        _onGroundFsm.AddTransition(OnGroundState.Pull,OnGroundState.Move,(state)=>!_player.CanPush());
        _onGroundFsm.SetStartState(OnGroundState.Idle);

        _onAirFsm.AddState(OnAirState.Fall,new PlayerFallState(_player));
        _onAirFsm.SetStartState(OnAirState.Fall);
        _fsm.Init();
    }


    private void UpdateFSM()
    {
        _fsm.OnLogic();
        _player.Move(_moveInput);
    }
   
    #endregion
}


